home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / src / indent.c < prev    next >
C/C++ Source or Header  |  1993-10-07  |  21KB  |  716 lines

  1. /* Indentation functions.
  2.    Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. #include "config.h"
  22. #include "lisp.h"
  23. #include "buffer.h"
  24. #include "indent.h"
  25. #include "frame.h"
  26. #include "window.h"
  27. #include "termchar.h"
  28. #include "termopts.h"
  29. #include "disptab.h"
  30.  
  31. #include "indent_p.h"
  32. #include "intervals_p.h"
  33. #include "insdel_p.h"
  34.  
  35. /* Indentation can insert tabs if this is non-zero;
  36.    otherwise always uses spaces */
  37. int indent_tabs_mode;
  38.  
  39. #define min(a, b) ((a) < (b) ? (a) : (b))
  40. #define max(a, b) ((a) > (b) ? (a) : (b))
  41.  
  42. #define CR 015
  43.  
  44. /* These three values memoize the current column to avoid recalculation */
  45. /* Some things in set last_known_column_point to -1
  46.   to mark the memoized value as invalid */
  47. /* Last value returned by current_column */
  48. int last_known_column;
  49. /* Value of point when current_column was called */
  50. int last_known_column_point;
  51. /* Value of MODIFF when current_column was called */
  52. int last_known_column_modified;
  53.  
  54. /* Get the display table to use for the current buffer.  */
  55.  
  56. struct Lisp_Vector *
  57. buffer_display_table ()
  58. {
  59.   Lisp_Object thisbuf;
  60.  
  61.   thisbuf = current_buffer->display_table;
  62.   if (XTYPE (thisbuf) == Lisp_Vector
  63.       && XVECTOR (thisbuf)->size == DISP_TABLE_SIZE)
  64.     return XVECTOR (thisbuf);
  65.   if (XTYPE (Vstandard_display_table) == Lisp_Vector
  66.       && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
  67.     return XVECTOR (Vstandard_display_table);
  68.   return 0;
  69. }
  70.  
  71. DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
  72.   "Return the horizontal position of point.  Beginning of line is column 0.\n\
  73. This is calculated by adding together the widths of all the displayed\n\
  74. representations of the character between the start of the previous line\n\
  75. and point.  (eg control characters will have a width of 2 or 4, tabs\n\
  76. will have a variable width)\n\
  77. Ignores finite width of frame, which means that this function may return\n\
  78. values greater than (frame-width).\n\
  79. Whether the line is visible (if `selective-display' is t) has no effect;\n\
  80. however, ^M is treated as end of line when `selective-display' is t.")
  81.   ()
  82. {
  83.   Lisp_Object temp;
  84.   XFASTINT (temp) = current_column ();
  85.   return temp;
  86. }
  87.  
  88. /* Cancel any recorded value of the horizontal position.  */
  89.  
  90. _VOID_
  91. invalidate_current_column ()
  92. {
  93.   last_known_column_point = 0;
  94. }
  95.  
  96. int
  97. current_column ()
  98. {
  99.   register int col;
  100.   register unsigned char *ptr, *stop;
  101.   register int tab_seen;
  102.   int post_tab;
  103.   register int c;
  104.   register int tab_width = XINT (current_buffer->tab_width);
  105.   int ctl_arrow = !NILP (current_buffer->ctl_arrow);
  106.   register struct Lisp_Vector *dp = buffer_display_table ();
  107.  
  108.   if (point == last_known_column_point
  109.       && MODIFF == last_known_column_modified)
  110.     return last_known_column;
  111.  
  112.   /* Make a pointer for decrementing through the chars before point.  */
  113.   ptr = &FETCH_CHAR (point - 1) + 1;
  114.   /* Make a pointer to where consecutive chars leave off,
  115.      going backwards from point.  */
  116.   if (point == BEGV)
  117.     stop = ptr;
  118.   else if (point <= GPT || BEGV > GPT)
  119.     stop = BEGV_ADDR;
  120.   else
  121.     stop = GAP_END_ADDR;
  122.  
  123.   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
  124.  
  125.   col = 0, tab_seen = 0, post_tab = 0;
  126.  
  127.   while (1)
  128.     {
  129.       if (ptr == stop)
  130.     {
  131.       /* We stopped either for the beginning of the buffer
  132.          or for the gap.  */
  133.       if (ptr == BEGV_ADDR)
  134.         break;
  135.       /* It was the gap.  Jump back over it.  */
  136.       stop = BEGV_ADDR;
  137.       ptr = GPT_ADDR;
  138.       /* Check whether that brings us to beginning of buffer.  */
  139.       if (BEGV >= GPT) break;
  140.     }
  141.  
  142.       c = *--ptr;
  143.       if (c >= 040 && c < 0177
  144.       && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
  145.     {
  146.       col++;
  147.     }
  148.       else if (c == '\n')
  149.     break;
  150.       else if (c == '\r' && EQ (current_buffer->selective_display, Qt))
  151.     break;
  152.       else if (c == '\t')
  153.     {
  154.       if (tab_seen)
  155.         col = ((col + tab_width) / tab_width) * tab_width;
  156.  
  157.       post_tab += col;
  158.       col = 0;
  159.       tab_seen = 1;
  160.     }
  161.       else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
  162.     col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
  163.       else
  164.     col += (ctl_arrow && c < 0200) ? 2 : 4;
  165.     }
  166.  
  167.   if (tab_seen)
  168.     {
  169.       col = ((col + tab_width) / tab_width) * tab_width;
  170.       col += post_tab;
  171.     }
  172.  
  173.   last_known_column = col;
  174.   last_known_column_point = point;
  175.   last_known_column_modified = MODIFF;
  176.  
  177.   return col;
  178. }
  179.  
  180.  
  181. DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
  182.   "Indent from point with tabs and spaces until COLUMN is reached.\n\
  183. Optional second argument MIN says always do at least MIN spaces\n\
  184. even if that goes past COLUMN; by default, MIN is zero.")
  185.   (col, minimum)
  186.      Lisp_Object col, minimum;
  187. {
  188.   int mincol;
  189.   register int fromcol;
  190.   register int tab_width = XINT (current_buffer->tab_width);
  191.  
  192.   CHECK_NUMBER (col, 0);
  193.   if (NILP (minimum))
  194.     XFASTINT (minimum) = 0;
  195.   CHECK_NUMBER (minimum, 1);
  196.  
  197.   fromcol = current_column ();
  198.   mincol = fromcol + XINT (minimum);
  199.   if (mincol < XINT (col)) mincol = XINT (col);
  200.  
  201.   if (fromcol == mincol)
  202.     return make_number (mincol);
  203.  
  204.   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
  205.  
  206.   if (indent_tabs_mode)
  207.     {
  208.       Lisp_Object n;
  209.       XFASTINT (n) = mincol / tab_width - fromcol / tab_width;
  210.       if (XFASTINT (n) != 0)
  211.     {
  212.       Finsert_char (make_number ('\t'), n);
  213.  
  214.       fromcol = (mincol / tab_width) * tab_width;
  215.     }
  216.     }
  217.  
  218.   XFASTINT (col) = mincol - fromcol;
  219.   Finsert_char (make_number (' '), col);
  220.  
  221.   last_known_column = mincol;
  222.   last_known_column_point = point;
  223.   last_known_column_modified = MODIFF;
  224.  
  225.   XSETINT (col, mincol);
  226.   return col;
  227. }
  228.  
  229. DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
  230.   0, 0, 0,
  231.   "Return the indentation of the current line.\n\
  232. This is the horizontal position of the character\n\
  233. following any initial whitespace.")
  234.   ()
  235. {
  236.   Lisp_Object val;
  237.  
  238.   XFASTINT (val) = position_indentation (find_next_newline (point, -1));
  239.   return val;
  240. }
  241.  
  242. int
  243. position_indentation (pos)
  244.      register int pos;
  245. {
  246.   register int column = 0;
  247.   register int tab_width = XINT (current_buffer->tab_width);
  248.   register unsigned char *p;
  249.   register unsigned char *stop;
  250.   
  251.   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
  252.   
  253.   stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
  254.   p = &FETCH_CHAR (pos);
  255.   while (1)
  256.     {
  257.       while (p == stop)
  258.     {
  259.       if (pos == ZV)
  260.         return column;
  261.       pos += p - &FETCH_CHAR (pos);
  262.       p = &FETCH_CHAR (pos);
  263.       stop = &FETCH_CHAR (BUFFER_CEILING_OF (pos)) + 1;
  264.     }
  265.       switch (*p++)
  266.     {
  267.     case ' ':
  268.       column++;
  269.       break;
  270.     case '\t':
  271.       column += tab_width - column % tab_width;
  272.       break;
  273.     default:
  274.       return column;
  275.     }
  276.     }
  277. }
  278.  
  279. DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
  280.   "Move point to column COLUMN in the current line.\n\
  281. The column of a character is calculated by adding together the widths\n\
  282. as displayed of the previous characters in the line.\n\
  283. This function ignores line-continuation;\n\
  284. there is no upper limit on the column number a character can have\n\
  285. and horizontal scrolling has no effect.\n\
  286. \n\
  287. If specified column is within a character, point goes after that character.\n\
  288. If it's past end of line, point goes to end of line.\n\n\
  289. A non-nil second (optional) argument FORCE means, if the line\n\
  290. is too short to reach column COLUMN then add spaces/tabs to get there,\n\
  291. and if COLUMN is in the middle of a tab character, change it to spaces.")
  292.   (column, force)
  293.      Lisp_Object column, force;
  294. {
  295.   register int pos;
  296.   register int col = current_column ();
  297.   register int goal;
  298.   register int end;
  299.   register int tab_width = XINT (current_buffer->tab_width);
  300.   register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
  301.   register struct Lisp_Vector *dp = buffer_display_table ();
  302.  
  303.   Lisp_Object val;
  304.   int prev_col;
  305.   int c;
  306.  
  307.   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
  308.   CHECK_NATNUM (column, 0);
  309.   goal = XINT (column);
  310.  
  311.   pos = point;
  312.   end = ZV;
  313.  
  314.   /* If we're starting past the desired column,
  315.      back up to beginning of line and scan from there.  */
  316.   if (col > goal)
  317.     {
  318.       pos = find_next_newline (pos, -1);
  319.       col = 0;
  320.     }
  321.  
  322.   while (col < goal && pos < end)
  323.     {
  324.       c = FETCH_CHAR (pos);
  325.       if (c == '\n')
  326.     break;
  327.       if (c == '\r' && EQ (current_buffer->selective_display, Qt))
  328.     break;
  329.       pos++;
  330.       if (c == '\t')
  331.     {
  332.       prev_col = col;
  333.       col += tab_width;
  334.       col = col / tab_width * tab_width;
  335.     }
  336.       else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
  337.     col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
  338.       else if (ctl_arrow && (c < 040 || c == 0177))
  339.         col++;
  340.       else if (c < 040 || c >= 0177)
  341.         col += 3;
  342.       else
  343.     col++;
  344.     }
  345.  
  346.   SET_PT (pos);
  347.  
  348.   /* If a tab char made us overshoot, change it to spaces
  349.      and scan through it again.  */
  350.   if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
  351.     {
  352.       int old_point;
  353.  
  354.       del_range (point - 1, point);
  355.       Findent_to (make_number (goal), Qnil);
  356.       old_point = point;
  357.       Findent_to (make_number (col), Qnil);
  358.       SET_PT (old_point);
  359.     }
  360.  
  361.   /* If line ends prematurely, add space to the end.  */
  362.   if (col < goal && !NILP (force))
  363.     Findent_to (make_number (col = goal), Qnil);
  364.  
  365.   last_known_column = col;
  366.   last_known_column_point = point;
  367.   last_known_column_modified = MODIFF;
  368.  
  369.   XFASTINT (val) = col;
  370.   return val;
  371. }
  372.  
  373. struct position val_compute_motion;
  374.  
  375. /* Scan the current buffer forward from offset FROM, pretending that
  376.    this is at line FROMVPOS, column FROMHPOS, until reaching buffer
  377.    offset TO or line TOVPOS, column TOHPOS (whichever comes first),
  378.    and return the ending buffer position and screen location.
  379.  
  380.    WIDTH is the number of columns available to display text;
  381.    compute_motion uses this to handle continuation lines and such.
  382.    HSCROLL is the number of columns not being displayed at the left
  383.    margin; this is usually taken from a window's hscroll member.
  384.    TAB_OFFSET is the number of columns of the first tab that aren't
  385.    being displayed, perhaps because of a continuation line or
  386.    something.
  387.  
  388.    compute_motion returns a pointer to a struct position.  The bufpos
  389.    member gives the buffer position at the end of the scan, and hpos
  390.    and vpos give its cartesian location.  I'm not clear on what the
  391.    other members are.
  392.  
  393.    For example, to find the buffer position of column COL of line LINE
  394.    of a certain window, pass the window's starting location as FROM
  395.    and the window's upper-left coordinates as FROMVPOS and FROMHPOS.
  396.    Pass the buffer's ZV as TO, to limit the scan to the end of the
  397.    visible section of the buffer, and pass LINE and COL as TOVPOS and
  398.    TOHPOS.  
  399.  
  400.    When displaying in window w, a typical formula for WIDTH is:
  401.  
  402.     window_width - 1
  403.      - (has_vertical_scroll_bars
  404.         ? VERTICAL_SCROLL_BAR_WIDTH
  405.         : (window_width + window_left != frame_width))
  406.  
  407.     where
  408.       window_width is XFASTINT (w->width),
  409.       window_left is XFASTINT (w->left),
  410.       has_vertical_scroll_bars is
  411.         FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
  412.       and frame_width = FRAME_WIDTH (XFRAME (window->frame))
  413.  
  414.     Or,
  415.       window_internal_width (w) - 1
  416.  
  417.    The `-1' accounts for the continuation-line backslashes; the rest
  418.    accounts for window borders if the window is split vertically, and
  419.    the scroll bars if the frame supports them.  */
  420.  
  421. struct position *
  422. compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset)
  423.      int from, fromvpos, fromhpos, to, tovpos, tohpos;
  424.      register int width;
  425.      int hscroll, tab_offset;
  426. {
  427.   register int hpos = fromhpos;
  428.   register int vpos = fromvpos;
  429.  
  430.   register int pos;
  431.   register int c;
  432.   register int tab_width = XFASTINT (current_buffer->tab_width);
  433.   register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
  434.   register struct Lisp_Vector *dp = buffer_display_table ();
  435.   int selective
  436.     = XTYPE (current_buffer->selective_display) == Lisp_Int
  437.       ? XINT (current_buffer->selective_display)
  438.     : !NILP (current_buffer->selective_display) ? -1 : 0;
  439.   int prev_vpos, prev_hpos;
  440.   int selective_rlen
  441.     = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
  442.        ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
  443.  
  444.   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
  445.   for (pos = from; pos < to; pos++)
  446.     {
  447.       /* Stop if past the target screen position.  */
  448.       if (vpos > tovpos
  449.       || (vpos == tovpos && hpos >= tohpos))
  450.     break;
  451.  
  452.       prev_vpos = vpos;
  453.       prev_hpos = hpos;
  454.  
  455.       c = FETCH_CHAR (pos);
  456.       if (c >= 040 && c < 0177
  457.       && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
  458.     hpos++;
  459.       else if (c == '\t')
  460.     {
  461.       hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0)
  462.                 /* Add tab_width here to make sure positive.
  463.                    hpos can be negative after continuation
  464.                    but can't be less than -tab_width.  */
  465.                 + tab_width)
  466.                    % tab_width);
  467.     }
  468.       else if (c == '\n')
  469.     {
  470.       if (selective > 0 && position_indentation (pos + 1) >= selective)
  471.         {
  472.           /* Skip any number of invisible lines all at once */
  473.           do
  474.         {
  475.           while (++pos < to && FETCH_CHAR (pos) != '\n');
  476.         }
  477.           while (pos < to && position_indentation (pos + 1) >= selective);
  478.           pos--;
  479.           /* Allow for the " ..." that is displayed for them. */
  480.           if (selective_rlen)
  481.         {
  482.           hpos += selective_rlen;
  483.           if (hpos >= width)
  484.             hpos = width;
  485.         }
  486.           /* We have skipped the invis text, but not the newline after.  */
  487.         }
  488.       else
  489.         {
  490.           /* A visible line.  */
  491.           vpos++;
  492.           hpos = 0;
  493.       hpos -= hscroll;
  494.       if (hscroll > 0) hpos++; /* Count the ! on column 0 */
  495.       tab_offset = 0;
  496.     }
  497.     }
  498.       else if (c == CR && selective < 0)
  499.     {
  500.       /* In selective display mode,
  501.          everything from a ^M to the end of the line is invisible */
  502.       while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
  503.       /* Stop *before* the real newline.  */
  504.       pos--;
  505.       /* Allow for the " ..." that is displayed for them. */
  506.       if (selective_rlen)
  507.         {
  508.           hpos += selective_rlen;
  509.           if (hpos >= width)
  510.         hpos = width;
  511.         }
  512.     }
  513.       else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
  514.     hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
  515.       else
  516.     hpos += (ctl_arrow && c < 0200) ? 2 : 4;
  517.  
  518.       /* Handle right margin.  */
  519.       if (hpos >= width
  520.       && (hpos > width
  521.           || (pos < ZV - 1
  522.           && FETCH_CHAR (pos + 1) != '\n')))
  523.     {
  524.       if (vpos > tovpos
  525.           || (vpos == tovpos && hpos >= tohpos))
  526.         break;
  527.       if (hscroll
  528.           || (truncate_partial_width_windows
  529.           && width + 1 < FRAME_WIDTH (selected_frame))
  530.           || !NILP (current_buffer->truncate_lines))
  531.         {
  532.           /* Truncating: skip to newline.  */
  533.           while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
  534.           pos--;
  535.           hpos = width;
  536.         }
  537.       else
  538.         {
  539.           /* Continuing.  */
  540.           vpos++;
  541.           hpos -= width;
  542.           tab_offset += width;
  543.         }
  544.  
  545.     }
  546.     }
  547.  
  548.   val_compute_motion.bufpos = pos;
  549.   val_compute_motion.hpos = hpos;
  550.   val_compute_motion.vpos = vpos;
  551.   val_compute_motion.prevhpos = prev_hpos;
  552.  
  553.   /* Nonzero if have just continued a line */
  554.   val_compute_motion.contin
  555.     = (pos != from
  556.        && (val_compute_motion.vpos != prev_vpos)
  557.        && c != '\n');
  558.  
  559.   return &val_compute_motion;
  560. }
  561.  
  562.  
  563. /* Return the column of position POS in window W's buffer,
  564.    rounded down to a multiple of the internal width of W.
  565.    This is the amount of indentation of position POS
  566.    that is not visible in its horizontal position in the window.  */
  567.  
  568. int
  569. pos_tab_offset (w, pos)
  570.      struct window *w;
  571.      register int pos;
  572. {
  573.   int opoint = point;
  574.   int col;
  575.   int width = window_internal_width (w) - 1;
  576.  
  577.   if (pos == BEGV || FETCH_CHAR (pos - 1) == '\n')
  578.     return 0;
  579.   SET_PT (pos);
  580.   col = current_column ();
  581.   SET_PT (opoint);
  582.   return col - (col % width);
  583. }
  584.  
  585. /* start_hpos is the hpos of the first character of the buffer:
  586.    zero except for the minibuffer window,
  587.    where it is the width of the prompt.  */
  588.  
  589. struct position val_vmotion;
  590.  
  591. struct position *
  592. vmotion (from, vtarget, width, hscroll, window)
  593.      register int from, vtarget, width;
  594.      int hscroll;
  595.      Lisp_Object window;
  596. {
  597.   struct position pos;
  598.   /* vpos is cumulative vertical position, changed as from is changed */
  599.   register int vpos = 0;
  600.   register int prevline;
  601.   register int first;
  602.   int lmargin = hscroll > 0 ? 1 - hscroll : 0;
  603.   int selective
  604.     = XTYPE (current_buffer->selective_display) == Lisp_Int
  605.       ? XINT (current_buffer->selective_display)
  606.     : !NILP (current_buffer->selective_display) ? -1 : 0;
  607.   int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
  608.  
  609.  retry:
  610.   if (vtarget > vpos)
  611.     {
  612.       /* Moving downward is simple, but must calculate from beg of line 
  613.      to determine hpos of starting point */
  614.       if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
  615.     {
  616.       prevline = find_next_newline (from, -1);
  617.       while (selective > 0
  618.          && prevline > BEGV
  619.          && position_indentation (prevline) >= selective)
  620.         prevline = find_next_newline (prevline - 1, -1);
  621.       pos = *compute_motion (prevline, 0,
  622.                  lmargin + (prevline == 1 ? start_hpos : 0),
  623.                  from, 1 << (INTBITS - 2), 0,
  624.                  width, hscroll, 0);
  625.     }
  626.       else
  627.     {
  628.       pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
  629.       pos.vpos = 0;
  630.     }
  631.       return compute_motion (from, vpos, pos.hpos,
  632.                  ZV, vtarget, - (1 << (INTBITS - 2)),
  633.                  width, hscroll, pos.vpos * width);
  634.     }
  635.  
  636.   /* To move upward, go a line at a time until
  637.      we have gone at least far enough */
  638.  
  639.   first = 1;
  640.  
  641.   while ((vpos > vtarget || first) && from > BEGV)
  642.     {
  643.       prevline = from;
  644.       while (1)
  645.     {
  646.       prevline = find_next_newline (prevline - 1, -1);
  647.       if (prevline == BEGV
  648.           || selective <= 0
  649.           || position_indentation (prevline) < selective)
  650.         break;
  651.     }
  652.       pos = *compute_motion (prevline, 0,
  653.                  lmargin + (prevline == 1 ? start_hpos : 0),
  654.                  from, 1 << (INTBITS - 2), 0,
  655.                  width, hscroll, 0);
  656.       vpos -= pos.vpos;
  657.       first = 0;
  658.       from = prevline;
  659.     }
  660.  
  661.   /* If we made exactly the desired vertical distance,
  662.      or if we hit beginning of buffer,
  663.      return point found */
  664.   if (vpos >= vtarget)
  665.     {
  666.       val_vmotion.bufpos = from;
  667.       val_vmotion.vpos = vpos;
  668.       val_vmotion.hpos = lmargin;
  669.       val_vmotion.contin = 0;
  670.       val_vmotion.prevhpos = 0;
  671.       return &val_vmotion;
  672.     }
  673.   
  674.   /* Otherwise find the correct spot by moving down */
  675.   goto retry;
  676. }
  677.  
  678. DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 1, 0,
  679.   "Move to start of screen line LINES lines down.\n\
  680. If LINES is negative, this is moving up.\n\
  681. Sets point to position found; this may be start of line\n\
  682.  or just the start of a continuation line.\n\
  683. Returns number of lines moved; may be closer to zero than LINES\n\
  684.  if beginning or end of buffer was reached.")
  685.   (lines)
  686.      Lisp_Object lines;
  687. {
  688.   struct position pos;
  689.   register struct window *w = XWINDOW (selected_window);
  690.   int width = window_internal_width (w) - 1;
  691.  
  692.   CHECK_NUMBER (lines, 0);
  693.  
  694.   pos = *vmotion (point, XINT (lines), width,
  695.           /* Not XFASTINT since perhaps could be negative */
  696.           XINT (w->hscroll), selected_window);
  697.  
  698.   SET_PT (pos.bufpos);
  699.   return make_number (pos.vpos);
  700. }
  701.  
  702. _VOID_
  703. syms_of_indent ()
  704. {
  705.   DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
  706.     "*Indentation can insert tabs if this is non-nil.\n\
  707. Setting this variable automatically makes it local to the current buffer.");
  708.   indent_tabs_mode = 1;
  709.  
  710.   defsubr (&Scurrent_indentation);
  711.   defsubr (&Sindent_to);
  712.   defsubr (&Scurrent_column);
  713.   defsubr (&Smove_to_column);
  714.   defsubr (&Svertical_motion);
  715. }
  716.